
use serde::{Deserialize, Serialize};

#[cfg(target_pointer_width = "64")]
pub type reg_t = u64;
#[cfg(target_pointer_width = "32")]
pub type reg_t = u32;

pub const RW_EXECUTE: reg_t = 0;
pub const RW_WRITE: reg_t = 1;
pub const RW_ACCESS: reg_t = 3;

pub const LEN_1: reg_t = 0;
pub const LEN_2: reg_t = 1;
pub const LEN_4: reg_t = 3;
pub const LEN_8: reg_t = 2;

pub const EFLAGS_TF: u32 = 0x100;
pub const EFLAGS_RF: u32 = 0x10000;

#[repr(C)]
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct X64Regs {
    pub rax: reg_t,
    pub rbx: reg_t,
    pub rcx: reg_t,
    pub rdx: reg_t,
    pub rbp: reg_t,
    pub rsp: reg_t,
    pub rsi: reg_t,
    pub rdi: reg_t,

    pub r8: reg_t,
    pub r9: reg_t,
    pub r10: reg_t,
    pub r11: reg_t,
    pub r12: reg_t,
    pub r13: reg_t,
    pub r14: reg_t,
    pub r15: reg_t,

    pub rip: reg_t,
    pub rflags: reg_t,
    pub cs: u16,
    pub ds: u16,
    pub es: u16,
    pub fs: u16,
    pub gs: u16,
    pub ss: u16,
}

#[repr(C)]
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct X86Regs {
    pub eax: reg_t,
    pub ebx: reg_t,
    pub ecx: reg_t,
    pub edx: reg_t,
    pub ebp: reg_t,
    pub esp: reg_t,
    pub esi: reg_t,
    pub edi: reg_t,
    pub eip: reg_t,
    pub eflags: reg_t,
    pub cs: u16,
    pub ds: u16,
    pub es: u16,
    pub fs: u16,
    pub gs: u16,
    pub ss: u16,
}

#[repr(C)]
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct ArmRegs {
    pub r0: reg_t,
    pub r1: reg_t,
    pub r2: reg_t,
    pub r3: reg_t,
    pub r4: reg_t,
    pub r5: reg_t,
    pub r6: reg_t,
    pub r7: reg_t,
    pub r8: reg_t,
    pub r9: reg_t,
    pub r10: reg_t,
    pub r11: reg_t,
    pub r12: reg_t,
    pub r13: reg_t,
    pub r14: reg_t,
    pub r15: reg_t,
}

#[repr(C)]
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct Arm64Regs {
    pub regs: [reg_t; 31],
    pub sp: reg_t,
    pub pc: reg_t,
    pub pstate: reg_t,
}

pub trait AbstractRegs {
    fn ip(&mut self) -> &mut reg_t;
    fn sp(&mut self) -> &mut reg_t;
}

impl AbstractRegs for X86Regs {
    fn ip(&mut self) -> &mut reg_t { &mut self.eip }
    fn sp(&mut self) -> &mut reg_t { &mut self.esp }
}

impl AbstractRegs for X64Regs {
    fn ip(&mut self) -> &mut reg_t { &mut self.rip }
    fn sp(&mut self) -> &mut reg_t { &mut self.rsp }
}

impl AbstractRegs for ArmRegs {
    fn ip(&mut self) -> &mut reg_t { &mut self.r15 }
    fn sp(&mut self) -> &mut reg_t { &mut self.r13 }
}

impl AbstractRegs for Arm64Regs {
    fn ip(&mut self) -> &mut reg_t { &mut self.pc }
    fn sp(&mut self) -> &mut reg_t { &mut self.sp }
}